#ifndef LABEL_H
#define LABEL_H

#include <QPixmap>
#include "widget.h"
#include "../../anime/utils.h"

class Label: public Widget, public AnimationObserver
{
public:
    enum TextAlignment {Left, Right, Center};
    enum VertAlignment {Top, Middle, Bottom};

    Label(Widget* _parent, Engine* _engine, QString _text, int _x, int _y, int _w, int _h,
          TextAlignment _textAlignment = Left)
        :Widget(_parent, _engine, _x, _y, _w, _h),
        backBrush(Qt::SolidPattern), showAnime(engine->fps, 1000), color(Qt::black),
        backColor(255, 255, 255, 255), font("Palatino", 12)
    {
        pixmap = new QPixmap(w, h);

        text = _text;
        penWidth = 0;
        penRed = 0;
        penGreen = 0;
        penBlue = 0;
        penAlpha = 255;

        backBrushRed = 0;
        backBrushGreen = 0;
        backBrushBlue = 0;
        backBrushAlpha = 0;

        SetFont(font);
        textAlignment = _textAlignment;
        vertAlignment = Middle;

        pen = new QPen();
        showBackground = false;
        underlined = false;

        Interpolable::RegisterProperty<int>(this, "penWidth", penWidth, &invalidated);
        Interpolable::RegisterProperty<int>(this, "penRed", penRed, &invalidated);
        Interpolable::RegisterProperty<int>(this, "penGreen", penGreen, &invalidated);
        Interpolable::RegisterProperty<int>(this, "penBlue", penBlue, &invalidated);
        Interpolable::RegisterProperty<int>(this, "penAlpha", penAlpha, &invalidated);
        Interpolable::RegisterProperty<int>(this, "backBrushRed", backBrushRed, &invalidated);
        Interpolable::RegisterProperty<int>(this, "backBrushGreen", backBrushGreen, &invalidated);
        Interpolable::RegisterProperty<int>(this, "backBrushBlue", backBrushBlue, &invalidated);
        Interpolable::RegisterProperty<int>(this, "backBrushAlpha", backBrushAlpha, &invalidated);

        g.AddInterpolator(showAnime.GetTime(), 0, 1000, Interpolable::GetProperty<int>(this, "penAlpha"), 0, 255);
        backInterpolatorId = g.AddInterpolator(showAnime.GetTime(), 0, 1000, Interpolable::GetProperty<int>(this, "backBrushAlpha"), 0, 255);
        g.Get(backInterpolatorId)->Disable();

        engine->AddAnimation(&showAnime);
        showAnime.SetDuration(300);
        showAnime.AddObserver(this);
    }

    virtual ~Label()
    {
        delete pixmap;
        delete pen;
    }

    virtual void doShow()
    {
        showAnime.Stop();
        paintEnabled = true;
        showAnime.Play();
    }

    virtual void doHide()
    {
        showAnime.Reverse(true);
        visible = false;
        showAnime.Play();
    }

    virtual void OnPause(Animation* a){};
    virtual void OnStop(Animation* a){};
    virtual void OnEnd(Animation* a)
    {
        if(a->IsReversed())
        {   // hiding
            paintEnabled = false;
            Hidden();
        }else
        {   // showing
            visible = true;
            Showed();
        }
    };

    virtual void OnPlay(Animation* a){};

    virtual void Paint(QPainter& widget_painter)
    {
        pixmap->fill(QColor(255, 255, 255, 0));
        QPainter painter(pixmap);

        // paints the background
        backColor.setRed(backBrushRed);
        backColor.setGreen(backBrushGreen);
        backColor.setBlue(backBrushBlue);
        backColor.setAlpha(backBrushAlpha);
        backBrush.setColor(backColor);
        painter.setBrush(backBrush);
        painter.setPen(QPen(QColor(0, 0, 0, 0)));
        painter.drawRect(-1, -1, w + 1, h + 1);

        // paints the text
        painter.setFont(font);
        color.setRed(penRed);
        color.setGreen(penGreen);
        color.setBlue(penBlue);
        color.setAlpha(penAlpha);
        pen->setColor(color);
        pen->setWidth(penWidth);
        painter.setPen(*pen);

        // calculates the text x and y position according to the chosen alignment
        int textX = 0;
        switch(textAlignment)
        {
        case Left:
            textX = 0;
            break;
        case Right:
            textX = w - textWidth;
            break;
        case Center:
            textX = w/2 - textWidth/2;
            break;
        }

        int textY = 0;
        switch(vertAlignment)
        {
        case Top:
            textY = textHeight;
            break;
        case Middle:
            textY = h - (h - textHeight)/2;
            break;
        case Bottom:
            textY = h;
            break;
        }
        painter.drawText(textX, textY, text);

        if(underlined)
        {
            painter.drawLine(textX, textY + 2, textX + textWidth, textY + 2);
        }

        widget_painter.drawPixmap(x, y, *pixmap, 0, 0, w, h);
    }

    virtual void SetFont(const QFont& _font)
    {
        QFontMetrics fm(_font);
        textHeight = fm.height() / 3 * 2;
        textWidth = fm.width(text);
        font = _font;
    }

    QString GetText(){ return text; }
    virtual void SetText(const QString& newText)
    {
        text = newText;
        QFontMetrics fm(font);
        textWidth = fm.width(text);
    }

    virtual void ShowBackground(bool show)
    {
        if(show == showBackground) return;
        if(!show)
        {
            backBrushAlpha = 0;
        }else
        {
            g.Get(backInterpolatorId)->SetMaxY(backBrushAlpha);
        }
        g.Get(backInterpolatorId)->SetEnabled(show);
    }

    int GetTextWidth(){ return textWidth; }

    int penRed;
    int penGreen;
    int penBlue;
    int penAlpha;
    int penWidth;

    bool underlined;

    TextAlignment textAlignment;
    VertAlignment vertAlignment;

    int backBrushRed;
    int backBrushGreen;
    int backBrushBlue;
    int backBrushAlpha;
    QBrush backBrush;

protected:
    IntGraph g;
    Animation showAnime;

    QString text;
    QColor color;
    QColor backColor;
    QFont font;
    QPen* pen;
    QPixmap* pixmap;

    int textHeight;
    int textWidth;

    bool showBackground;
    int backInterpolatorId;
};

#endif // LABEL_H
